package com.hitqz.robot.camera.module;

import cn.hutool.core.collection.CollUtil;
import com.hitqz.robot.camera.common.AreaTemplateMeasurement;
import com.hitqz.robot.camera.common.ThermalCommon;
import com.hitqz.robot.camera.lib.ImageAlgLib;
import com.hitqz.robot.camera.lib.NetSDKLib;
import com.hitqz.robot.camera.lib.NetSDKLib.*;
import com.hitqz.robot.camera.lib.ToolKits;
import com.hitqz.robot.camera.lib.Utils;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j
public class ThermalCameraModule {
	
	static ImageAlgLib imageAlgApi = ImageAlgLib.IMAGEALG_INSTANCE;
	
	public static class ThermalCameraStatus {
		public boolean bSearching = false;				   			// 是否正在查找
		public int     nFinderHanle;                      			// 取到的查询句柄
		public int     nTotalCount;                       			// 符合此次查询条件的结果总条数
		public LLong hRadiometryHandle = new LLong(0); // 订阅句柄
	}
	
	private static ThermalCameraStatus status = new ThermalCameraStatus();
	
	/**
	 * 订阅温度分布数据（热图）
	 */
	public static boolean radiometryAttach(LLong m_hLoginHandle, int nChannel, fRadiometryAttachCB cbNotify) {
		/*
		 * 入参
		 */
		NET_IN_RADIOMETRY_ATTACH stIn = new NET_IN_RADIOMETRY_ATTACH();
		stIn.nChannel = nChannel;  // 通道号
		stIn.cbNotify = cbNotify;  // 回调函数
		
		/*
		 * 出参
		 */
		NET_OUT_RADIOMETRY_ATTACH stOut = new NET_OUT_RADIOMETRY_ATTACH();
		status.hRadiometryHandle = LoginModule.netsdk.CLIENT_RadiometryAttach(m_hLoginHandle, stIn, stOut, 3000);
		
		if(status.hRadiometryHandle.longValue() == 0) {
        	System.err.printf("RadiometryAttach Failed!" + ToolKits.getErrorCodePrint());
        }
		
		return status.hRadiometryHandle.longValue() != 0;
	}
	
	/**
	 * 获取查询总个数
	 */
	public static boolean isAttaching() {
		return status.hRadiometryHandle.longValue() != 0;
	}
	
	/**
	 * 开始获取热图数据
	 */
	public static int radiometryFetch(LLong m_hLoginHandle,int nChannel) {
		
		int nStatus = -1;
		
		/*
		 * 入参
		 */
		NET_IN_RADIOMETRY_FETCH stIn = new NET_IN_RADIOMETRY_FETCH();
		stIn.nChannel = nChannel;  // 通道号
		
		/*
		 * 出参
		 */
		NET_OUT_RADIOMETRY_FETCH stOut = new NET_OUT_RADIOMETRY_FETCH();
		
		if(!LoginModule.netsdk.CLIENT_RadiometryFetch(m_hLoginHandle, stIn, stOut, 3000)) {
        	System.err.printf("RadiometryFetch Failed!" + ToolKits.getErrorCodePrint());
		} else {
			nStatus = stOut.nStatus;
		}
		
		return nStatus;
	}
	
	/**
	 * 处理回调数据（热图）
	 * @throws IOException 
	 */
	public static boolean saveData(NET_RADIOMETRY_DATA radiometryData) throws IOException {
		
		if (radiometryData == null) {
			return false;
		}
		
		int nWidth = radiometryData.stMetaData.nWidth;
		int nHeight = radiometryData.stMetaData.nHeight;
		
		short[] pGrayImg = new short[nWidth * nHeight];
		float[] pTempForPixels = new float[nWidth * nHeight];
		
		if(LoginModule.netsdk.CLIENT_RadiometryDataParse(radiometryData, pGrayImg, pTempForPixels)) {
			byte[] pYData = new byte[nWidth*nHeight*2];
			imageAlgApi.drcTable(pGrayImg, (short)nWidth, (short)nHeight, 0, pYData, null);
			ToolKits.savePicture(pYData, "./GrayscaleMap.yuv");
		} else {
			System.err.println("saveData failed!" + ToolKits.getErrorCodePrint());
			return false;
		}
		
		return true;
	}
	
	/**
	 * 取消订阅温度分布数据
	 */
	public static void radiometryDetach() {
		if(status.hRadiometryHandle.longValue() != 0) {
			LoginModule.netsdk.CLIENT_RadiometryDetach(status.hRadiometryHandle);
			status.hRadiometryHandle.setValue(0);
		}
	}
	
	/**
	 * 查询测温点
	 */
	public static NET_RADIOMETRYINFO queryPointTemper(LLong m_hLoginHandle,int nChannel, short x, short y) {
		int nQueryType = NetSDKLib.NET_QUERY_DEV_RADIOMETRY_POINT_TEMPER;

		// 入参
		NET_IN_RADIOMETRY_GETPOINTTEMPER stIn = new NET_IN_RADIOMETRY_GETPOINTTEMPER();
		stIn.nChannel = nChannel;
		stIn.stCoordinate.nx = x;
		stIn.stCoordinate.ny = y;
		
		// 出参
		NET_OUT_RADIOMETRY_GETPOINTTEMPER stOut = new NET_OUT_RADIOMETRY_GETPOINTTEMPER();
	
		stIn.write();
		stOut.write();
    	boolean bRet = LoginModule.netsdk.CLIENT_QueryDevInfo(m_hLoginHandle, nQueryType, stIn.getPointer(), stOut.getPointer(), null, 3000);
		if(!bRet) {
        	log.error("QueryPointTemper Failed!" + ToolKits.getErrorCodePrint());
        	return null;
		}
		
		stOut.read();
		return stOut.stPointTempInfo;
	}
	
	/**
	 * 查询测温项
	 */
	public static NET_RADIOMETRYINFO queryItemTemper(LLong m_hLoginHandle,int nChannel, int nPresetId, int nRuleId, int nMeterType) {
		int nQueryType = NetSDKLib.NET_QUERY_DEV_RADIOMETRY_TEMPER;
		
		// 入参
		NET_IN_RADIOMETRY_GETTEMPER stIn = new NET_IN_RADIOMETRY_GETTEMPER();
		stIn.stCondition.nPresetId = nPresetId;
		stIn.stCondition.nRuleId = nRuleId;
		stIn.stCondition.nMeterType = nMeterType; 	// eg: NET_RADIOMETRY_METERTYPE.NET_RADIOMETRY_METERTYPE_AREA;
		stIn.stCondition.nChannel = nChannel;

		// 出参
		NET_OUT_RADIOMETRY_GETTEMPER stOut = new NET_OUT_RADIOMETRY_GETTEMPER();
	
		stIn.write();
		stOut.write();
    	boolean bRet = LoginModule.netsdk.CLIENT_QueryDevInfo(m_hLoginHandle, nQueryType, stIn.getPointer(), stOut.getPointer(), null, 3000);
		if(!bRet) {
        	log.error("queryItemTemper Failed!" + ToolKits.getErrorCodePrint());
        	return null;
		}
		
		stOut.read();
		return stOut.stTempInfo;
	}
	
	/**
	 * 开始查询信息
	 */
	public static boolean startFind(LLong m_hLoginHandle,NET_IN_RADIOMETRY_STARTFIND stuIn) {
		if(status.bSearching) {
			stopFind(m_hLoginHandle);
		}
		
		/*
		 * 出参
		 */
		NET_OUT_RADIOMETRY_STARTFIND stuOut = new NET_OUT_RADIOMETRY_STARTFIND();
		stuIn.write();
		stuOut.write();
		status.bSearching = LoginModule.netsdk.CLIENT_StartFind(m_hLoginHandle,
				NET_FIND.NET_FIND_RADIOMETRY, stuIn.getPointer(), stuOut.getPointer(), 5000);
		if (status.bSearching) {
			stuOut.read();
			status.nFinderHanle = stuOut.nFinderHanle;
			status.nTotalCount = stuOut.nTotalCount;
		}else {
			System.err.printf("startFind Failed!" + ToolKits.getErrorCodePrint());
		}
		
		return status.bSearching;
	}
	
	/**
	 * 获取查询总个数
	 */
	public static int getTotalCount() {
		return status.nTotalCount;
	}
	
	/**
	 * 查询信息
	 */
	public static NET_OUT_RADIOMETRY_DOFIND doFind(LLong m_hLoginHandle,int nOffset, int nCount) {
		if(!status.bSearching) {
			System.err.printf("DoFind Failed! [need startFind]");
			return null;
		}
		
		/*
		 * 入参
		 */
		NET_IN_RADIOMETRY_DOFIND stuIn = new NET_IN_RADIOMETRY_DOFIND();
		stuIn.nFinderHanle = status.nFinderHanle;
		stuIn.nBeginNumber = nOffset;
		stuIn.nCount = nCount;
		
		/*
		 * 出参
		 */
		NET_OUT_RADIOMETRY_DOFIND stuOut = new NET_OUT_RADIOMETRY_DOFIND();
		
		stuIn.write();
		stuOut.write();
		if (!LoginModule.netsdk.CLIENT_DoFind(m_hLoginHandle,
				NET_FIND.NET_FIND_RADIOMETRY, stuIn.getPointer(), stuOut.getPointer(), 5000)) {
			System.err.printf("DoFind Failed!" + ToolKits.getErrorCodePrint());
			return null;
		}
		
		stuOut.read();
		return stuOut;
	}
	
	/**
	 * 停止查询信息
	 */
	public static void stopFind(LLong m_hLoginHandle) {
		if(!status.bSearching) {
			return;
		}
		
		/*
		 * 入参
		 */
		NET_IN_RADIOMETRY_STOPFIND stuIn = new NET_IN_RADIOMETRY_STOPFIND();
		stuIn.nFinderHanle = status.nFinderHanle;
		
		/*
		 * 出参
		 */
		NET_OUT_RADIOMETRY_STOPFIND stuOut = new NET_OUT_RADIOMETRY_STOPFIND();
		
		stuIn.write();
		stuOut.write();
		LoginModule.netsdk.CLIENT_StopFind(m_hLoginHandle,
				NET_FIND.NET_FIND_RADIOMETRY, stuIn.getPointer(), stuOut.getPointer(), 5000);
		
		status.bSearching = false;
		status.nFinderHanle = 0;
//		status.nTotalCount = 0;
		
		return;
	}

	/**
	 * 查询当前测温规则
	 */
	public static void getThermometryRule(LLong m_hLoginHandle, int queryChannel, CFG_RADIOMETRY_RULE_INFO config) {

		String command = NetSDKLib.CFG_CMD_THERMOMETRY_RULE;

		boolean ret = ToolKits.GetDevConfig(m_hLoginHandle, queryChannel, command, config);

		if (!ret) {
			log.error("获取热成像测温规则配置失败：" + ToolKits.getErrorCodePrint());
			return;
		}

		StringBuilder builder = new StringBuilder().append("\n<<-----当前热成像配置----->>");
		for (int i = 0; i < config.nCount; ++i) {
			try {  // 预置点是球机的概念(指球机运动到的某一个精确点的编号)，BF系列是枪机没有这个设定，所以固定是 0
				builder.append("\n").append("///----->规则配置[").append(i).append("]: ").append("\n")
						.append("预置点编号: ").append(config.stRule[i].nPresetId).append("\n")
						.append("规则编号: ").append(config.stRule[i].nRuleId).append("\n")
						.append("规则名称: ").append(new String(config.stRule[i].szName, Utils.getPlatformEncode()).trim()).append("\n")
						.append("使能: ").append(config.stRule[i].bEnable == 0 ? "否" : "是").append("\n")
						.append("测温模式: ").append(ThermalCommon.ArrMeterType.getNoteByValue(config.stRule[i].nMeterType)).append("\n")
						.append("模式子类型: ").append(ThermalCommon.AreaSubtype.getNoteByValue(config.stRule[i].emAreaSubType)).append("\n")
						.append("温度采样周期(秒): ").append(config.stRule[i].nSamplePeriod).append("\n");

				// 规则坐标点配置
				builder.append("//--->共有: ").append(config.stRule[i].nCoordinateCnt).append(" 个测温点，测温点坐标详细: ").append("\n");
				for (int j = 0; j < config.stRule[i].nCoordinateCnt; j++) {
					builder.append("坐标[").append(j).append("]: ")
							.append(String.format("[%04d,%04d]", config.stRule[i].stCoordinates[j].nX, config.stRule[i].stCoordinates[j].nY)).append("\n");
				}
				// 报警相关配置(本地参数)
				builder.append("//--->本地参数配置: ").append("\n")
						.append("是否启用本地配置: ").append(config.stRule[i].stLocalParameters.bEnable == 0 ? "否" : "是").append("\n")
						.append("目标辐射系数: ").append(config.stRule[i].stLocalParameters.fObjectEmissivity).append("\n")
						.append("目标距离: ").append(config.stRule[i].stLocalParameters.nObjectDistance).append("\n")
						.append("目标反射温度: ").append(config.stRule[i].stLocalParameters.nRefalectedTemp).append("\n");

				// 报警相关配置(测温点报警)
				builder.append("//--->共有: ").append(config.stRule[i].nAlarmSettingCnt).append(" 测温点报警设置: ").append("\n");
				for (int j = 0; j < config.stRule[i].nAlarmSettingCnt; j++) {
					builder.append("配置[").append(j).append("]: ").append("\n")
							.append("是否启用: ").append(config.stRule[i].stAlarmSetting[j].bEnable == 0 ? "否" : "是").append("\n")
							.append("报警唯一编号: ").append(config.stRule[i].stAlarmSetting[j].nId).append("\n")
							.append("测温报警结果类型: ").append(ThermalCommon.AlarmType.getNoteByValue(config.stRule[i].stAlarmSetting[j].nResultType)).append("\n")
							.append("报警条件: ").append(ThermalCommon.AlarmResultType.getNoteByValue(config.stRule[i].stAlarmSetting[j].nAlarmCondition)).append("\n")
							.append("报警阈值温度: ").append(config.stRule[i].stAlarmSetting[j].fThreshold).append("\n")
							.append("温度误差: ").append(config.stRule[i].stAlarmSetting[j].fHysteresis).append("\n")
							.append("阈值温度持续时间(秒): ").append(config.stRule[i].stAlarmSetting[j].nDuration).append("\n");
				}

			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		log.info(builder.toString());
	}

	/**
	 * 设置测温规则
	 */
	public static void setThermometryRule(LLong m_hLoginHandle, int queryChannel, int nPresetId, AreaTemplateMeasurement area, int enable, CFG_RADIOMETRY_RULE_INFO config) {
		/**
		 * 配置内所有的参数都会填写，且尽可能的和网页匹配
		 */

		// 配置前最好获取一下旧的配置，如果只是修改就不需要大费周章的所有参数都填一遍了
		String command = NetSDKLib.CFG_CMD_THERMOMETRY_RULE;

		boolean ret = ToolKits.GetDevConfig(m_hLoginHandle, queryChannel, command, config);

		if (!ret) {
			log.error("获取热成像测温规则配置失败：" + ToolKits.getErrorCodePrint());
			return;
		}

		// 当然本Demo会把所有参数都填一遍以供参考
		// 举行规则配置
        SetThermometryRectangleRule(nPresetId,area,enable,config);

		boolean ret2 = ToolKits.SetDevConfig(m_hLoginHandle, queryChannel, command, config);
		if (!ret2) {
			log.error("设置热成像测温规则失败!" + ToolKits.getErrorCodePrint());
			return;
		}
		log.info("设置热成像测温规则成功!");
	}

	/**
	 * 设置测温规则
	 */
	public static void setMutilThermometryRule(LLong m_hLoginHandle, int queryChannel, int nPresetId, List<AreaTemplateMeasurement> area, int enable, CFG_RADIOMETRY_RULE_INFO config) {
		/**
		 * 配置内所有的参数都会填写，且尽可能的和网页匹配
		 */

		// 配置前最好获取一下旧的配置，如果只是修改就不需要大费周章的所有参数都填一遍了
		String command = NetSDKLib.CFG_CMD_THERMOMETRY_RULE;
		//fixme 配置全局只取一次 看能不能节省时间
		if (config==null || config.nCount==0 || config.stRule.length==0) {
			boolean ret = ToolKits.GetDevConfig(m_hLoginHandle, queryChannel, command, config);
			log.info("获取测温规则-----");
			if (!ret) {
				log.error("获取热成像测温规则配置失败：" + ToolKits.getErrorCodePrint());
				return;
			}
		}

		// 当然本Demo会把所有参数都填一遍以供参考
		// 举行规则配置
		SetMultiThermometryRectangleRule(nPresetId,area,enable,config);

		boolean ret2 = ToolKits.SetDevConfig(m_hLoginHandle, queryChannel, command, config);
		if (!ret2) {
			log.error("设置热成像测温规则失败!" + ToolKits.getErrorCodePrint());
			return;
		}
		log.info("设置热成像测温规则成功!");
	}


	/**
	 * 方形规则配置
	 * @param nPresetId  预置点 枪机0 云台型的需要填
	 * @param areaList 测温区域数据
	 * @param enable 0 关闭,1启用  要测温度的时候设置1，测完后设置0
	 * @param config
	 */
	private static void SetMultiThermometryRectangleRule(int nPresetId, List<AreaTemplateMeasurement> areaList, int enable , CFG_RADIOMETRY_RULE_INFO config) {
		log.info("config.nCount"+config.nCount);
		for (int i = 0; i < config.nCount; i++) {
			//初始化掉已经设定的
			config.stRule[i] = new CFG_RADIOMETRY_RULE();
		}

		//每次都改第一条去覆盖
		int i = 0;
		if (areaList==null || areaList.isEmpty() || Objects.equals(areaList.get(0).getCheckItemId(),0)){
			log.info("默认规则");
			setDefaultRule(nPresetId, config);
			return;
		}
		config.nCount = areaList.size();
		for (AreaTemplateMeasurement  area: CollUtil.emptyIfNull(areaList)) {
			// 通用配置 todo 枪机没有预置点怎么判定（7号楼的）
			config.stRule[i].nPresetId = nPresetId;   // 枪机没有预置点的说法，固定为0,云台有预置点
			config.stRule[i].nRuleId = i + 1;     // 规则编号,从 1 开始
			String areaName = Optional.ofNullable(area).map(AreaTemplateMeasurement::getAreaName).orElse("Rectangle" + i);
			System.arraycopy(areaName.getBytes(), 0, config.stRule[i].szName, 0, areaName.getBytes().length);  // 规则名称
			config.stRule[i].bEnable = enable; // 0 false,1 true
			config.stRule[i].nMeterType = NET_RADIOMETRY_METERTYPE.NET_RADIOMETRY_METERTYPE_AREA;  // 区域模式
			config.stRule[i].emAreaSubType = EM_CFG_AREA_SUBTYPE.EM_CFG_AREA_SUBTYPE_RECT;      // 方形模式
			config.stRule[i].nSamplePeriod = 3; //温度采样周期(秒)

			// 规则坐标点配置 [0891,4361] [2616,4361] [2616,6720] [0891,6720]
			config.stRule[i].nCoordinateCnt = 4; // 五个坐标
			String bottomLeftPos = Optional.ofNullable(area).map(AreaTemplateMeasurement::getBottomLeftPos).orElse("0,0");
			String bottomRightPos = Optional.ofNullable(area).map(AreaTemplateMeasurement::getBottomRightPos).orElse("8192,0");
			String upperRightPos = Optional.ofNullable(area).map(AreaTemplateMeasurement::getUpperRightPos).orElse("8192,8192");
			String upperLeftPos = Optional.ofNullable(area).map(AreaTemplateMeasurement::getUpperLeftPos).orElse("0,8192");

			config.stRule[i].stCoordinates[0].nX = Math.min(Integer.parseInt(bottomLeftPos.split(",")[0]),8191);
			config.stRule[i].stCoordinates[0].nY = Math.min(Integer.parseInt(bottomLeftPos.split(",")[1]),8191);
			config.stRule[i].stCoordinates[1].nX = Math.min(Integer.parseInt(bottomRightPos.split(",")[0]),8191);
			config.stRule[i].stCoordinates[1].nY = Math.min(Integer.parseInt(bottomRightPos.split(",")[1]),8191);
			config.stRule[i].stCoordinates[2].nX = Math.min(Integer.parseInt(upperRightPos.split(",")[0]),8191);
			config.stRule[i].stCoordinates[2].nY = Math.min(Integer.parseInt(upperRightPos.split(",")[1]),8191);
			config.stRule[i].stCoordinates[3].nX = Math.min(Integer.parseInt(upperLeftPos.split(",")[0]),8191);
			config.stRule[i].stCoordinates[3].nY = Math.min(Integer.parseInt(upperLeftPos.split(",")[1]),8191);

			// 报警相关配置(本地参数)
			config.stRule[i].stLocalParameters.bEnable = 0;    // 0 false,1 true  不需要启用的话这里至 0
			config.stRule[i].stLocalParameters.fObjectEmissivity = 0.97f;   // 目标辐射系数
			config.stRule[i].stLocalParameters.nObjectDistance = 2; // 目标距离
			config.stRule[i].stLocalParameters.nRefalectedTemp = 25; // 目标反射温度

			// 报警相关配置(测温点报警) Demo里只配置一条
			config.stRule[i].nAlarmSettingCnt = 1;
			config.stRule[i].stAlarmSetting[0].bEnable = 0; // 0 false,1 true  不需要启用的话这里至 0
			// 点测温：具体值，
			// 线测温：最大, 最小, 平均
			// 区域测温：最大, 最小, 平均, 标准, 中间, ISO
			config.stRule[i].stAlarmSetting[0].nResultType = CFG_STATISTIC_TYPE.CFG_STATISTIC_TYPE_MAX; // 最大
			config.stRule[i].stAlarmSetting[0].nAlarmCondition = CFG_COMPARE_RESULT.CFG_COMPARE_RESULT_BELOW; // 低于
			config.stRule[i].stAlarmSetting[0].fThreshold = 20.0f;  // 报警阈值温度
			config.stRule[i].stAlarmSetting[0].fHysteresis = 0.1f;  // 温度误差
			config.stRule[i].stAlarmSetting[0].nDuration = 30;      // 阈值温度持续时间(秒)
			i++;
		}
	}

	/**
	 * 方形规则配置
	 * @param nPresetId  预置点 枪机0 云台型的需要填
	 * @param area 测温区域数据
	 * @param enable 0 关闭,1启用  要测温度的时候设置1，测完后设置0
	 * @param config
	 */
	private static void SetThermometryRectangleRule(int nPresetId, AreaTemplateMeasurement area, int enable , CFG_RADIOMETRY_RULE_INFO config) {
		//每次都改第一条去覆盖
		int i = 0;
		/**
		 * 预置点编号: 0
		 * 规则编号: 4
		 * 规则名称: Rectangle1
		 * 使能: 是
		 * 测温模式: 区域
		 * 模式子类型: 矩形
		 * 温度采样周期(秒): 3
		 * //--->共有: 4 个测温点，测温点坐标详细:
		 * 坐标[0]: [0891,4361]
		 * 坐标[1]: [2616,4361]
		 * 坐标[2]: [2616,6720]
		 * 坐标[3]: [0891,6720]
		 * //--->本地参数配置:
		 * 是否启用本地配置: 是
		 * 目标辐射系数: 0.97
		 * 目标距离: 2
		 * 目标反射温度: 25
		 * //--->共有: 1 测温点报警设置:
		 * 配置[0]:
		 * 是否启用: 是
		 * 报警唯一编号: 0
		 * 测温报警结果类型: 最大
		 * 报警条件: 低于
		 * 报警阈值温度: 20.0
		 * 温度误差: 0.1
		 * 阈值温度持续时间(秒): 30
		 */
		if (area==null){
			enable = 0;
		}
		// 通用配置 todo 枪机没有预置点怎么判定（7号楼的）
		config.stRule[i].nPresetId = nPresetId;   // 枪机没有预置点的说法，固定为0,云台有预置点
		config.stRule[i].nRuleId = i + 1;     // 规则编号,从 1 开始
		System.arraycopy("Rectangle1".getBytes(), 0, config.stRule[i].szName, 0, "Rectangle1".length());  // 规则名称
		config.stRule[i].bEnable = enable; // 0 false,1 true
		config.stRule[i].nMeterType = NET_RADIOMETRY_METERTYPE.NET_RADIOMETRY_METERTYPE_AREA;  // 区域模式
		config.stRule[i].emAreaSubType = EM_CFG_AREA_SUBTYPE.EM_CFG_AREA_SUBTYPE_RECT;      // 方形模式
		config.stRule[i].nSamplePeriod = 3; //温度采样周期(秒)

		// 规则坐标点配置 [0891,4361] [2616,4361] [2616,6720] [0891,6720]
		config.stRule[i].nCoordinateCnt = 4; // 五个坐标
		String bottomLeftPos = Optional.ofNullable(area).map(AreaTemplateMeasurement::getBottomLeftPos).orElse("0,0");
		String bottomRightPos = Optional.ofNullable(area).map(AreaTemplateMeasurement::getBottomRightPos).orElse("8192,0");
		String upperRightPos = Optional.ofNullable(area).map(AreaTemplateMeasurement::getUpperRightPos).orElse("8192,8192");
		String upperLeftPos = Optional.ofNullable(area).map(AreaTemplateMeasurement::getUpperLeftPos).orElse("0,8192");

//		config.stRule[i].stCoordinates[0].nX = 0;
//		config.stRule[i].stCoordinates[0].nY = 0;
//		config.stRule[i].stCoordinates[1].nX = 8191;
//		config.stRule[i].stCoordinates[1].nY = 0;
//		config.stRule[i].stCoordinates[2].nX = 8191;
//		config.stRule[i].stCoordinates[2].nY = 8191;
//		config.stRule[i].stCoordinates[3].nX = 0;
//		config.stRule[i].stCoordinates[3].nY = 8191;
		config.stRule[i].stCoordinates[0].nX = Math.min(Integer.parseInt(bottomLeftPos.split(",")[0]),8191);
		config.stRule[i].stCoordinates[0].nY = Math.min(Integer.parseInt(bottomLeftPos.split(",")[1]),8191);
		config.stRule[i].stCoordinates[1].nX = Math.min(Integer.parseInt(bottomRightPos.split(",")[0]),8191);
		config.stRule[i].stCoordinates[1].nY = Math.min(Integer.parseInt(bottomRightPos.split(",")[1]),8191);
		config.stRule[i].stCoordinates[2].nX = Math.min(Integer.parseInt(upperRightPos.split(",")[0]),8191);
		config.stRule[i].stCoordinates[2].nY = Math.min(Integer.parseInt(upperRightPos.split(",")[1]),8191);
		config.stRule[i].stCoordinates[3].nX = Math.min(Integer.parseInt(upperLeftPos.split(",")[0]),8191);
		config.stRule[i].stCoordinates[3].nY = Math.min(Integer.parseInt(upperLeftPos.split(",")[1]),8191);
//		config.stRule[i].stCoordinates[0].nX = 891;
//		config.stRule[i].stCoordinates[0].nY = 4361;
//		config.stRule[i].stCoordinates[1].nX = 2616;
//		config.stRule[i].stCoordinates[1].nY = 4361;
//		config.stRule[i].stCoordinates[2].nX = 2616;
//		config.stRule[i].stCoordinates[2].nY = 6720;
//		config.stRule[i].stCoordinates[3].nX = 891;
//		config.stRule[i].stCoordinates[3].nY = 6720;

		// 报警相关配置(本地参数)
		config.stRule[i].stLocalParameters.bEnable = 0;    // 0 false,1 true  不需要启用的话这里至 0
		config.stRule[i].stLocalParameters.fObjectEmissivity = 0.97f;   // 目标辐射系数
		config.stRule[i].stLocalParameters.nObjectDistance = 2; // 目标距离
		config.stRule[i].stLocalParameters.nRefalectedTemp = 25; // 目标反射温度

		// 报警相关配置(测温点报警) Demo里只配置一条
		config.stRule[i].nAlarmSettingCnt = 1;
		config.stRule[i].stAlarmSetting[0].bEnable = 0; // 0 false,1 true  不需要启用的话这里至 0
		// 点测温：具体值，
		// 线测温：最大, 最小, 平均
		// 区域测温：最大, 最小, 平均, 标准, 中间, ISO
		config.stRule[i].stAlarmSetting[0].nResultType = CFG_STATISTIC_TYPE.CFG_STATISTIC_TYPE_MAX; // 最大
		config.stRule[i].stAlarmSetting[0].nAlarmCondition = CFG_COMPARE_RESULT.CFG_COMPARE_RESULT_BELOW; // 低于
		config.stRule[i].stAlarmSetting[0].fThreshold = 20.0f;  // 报警阈值温度
		config.stRule[i].stAlarmSetting[0].fHysteresis = 0.1f;  // 温度误差
		config.stRule[i].stAlarmSetting[0].nDuration = 30;      // 阈值温度持续时间(秒)
	}




	/**
	 * 方形规则配置
	 * @param nPresetId  预置点 枪机0 云台型的需要填
	 * @param config
	 */
	private static void setDefaultRule(int nPresetId, CFG_RADIOMETRY_RULE_INFO config) {
		int i = 0;
		config.nCount = 1;
		/**
		 * 预置点编号: 0
		 * 规则编号: 4
		 * 规则名称: Rectangle1
		 * 使能: 是
		 * 测温模式: 区域
		 * 模式子类型: 矩形
		 * 温度采样周期(秒): 3
		 * //--->共有: 4 个测温点，测温点坐标详细:
		 * 坐标[0]: [0891,4361]
		 * 坐标[1]: [2616,4361]
		 * 坐标[2]: [2616,6720]
		 * 坐标[3]: [0891,6720]
		 * //--->本地参数配置:
		 * 是否启用本地配置: 是
		 * 目标辐射系数: 0.97
		 * 目标距离: 2
		 * 目标反射温度: 25
		 * //--->共有: 1 测温点报警设置:
		 * 配置[0]:
		 * 是否启用: 是
		 * 报警唯一编号: 0
		 * 测温报警结果类型: 最大
		 * 报警条件: 低于
		 * 报警阈值温度: 20.0
		 * 温度误差: 0.1
		 * 阈值温度持续时间(秒): 30
		 */
		// 通用配置 todo 枪机没有预置点怎么判定（7号楼的）
		config.stRule[i].nPresetId = nPresetId;   // 枪机没有预置点的说法，固定为0,云台有预置点
		config.stRule[i].nRuleId = i + 1;     // 规则编号,从 1 开始
		System.arraycopy("default".getBytes(), 0, config.stRule[i].szName, 0, "default".length());  // 规则名称
		config.stRule[i].bEnable = 0; // 0 false,1 true
		config.stRule[i].nMeterType = NET_RADIOMETRY_METERTYPE.NET_RADIOMETRY_METERTYPE_AREA;  // 区域模式
		config.stRule[i].emAreaSubType = EM_CFG_AREA_SUBTYPE.EM_CFG_AREA_SUBTYPE_RECT;      // 方形模式
		config.stRule[i].nSamplePeriod = 3; //温度采样周期(秒)

		// 规则坐标点配置 [0891,4361] [2616,4361] [2616,6720] [0891,6720]
		config.stRule[i].nCoordinateCnt = 4; // 五个坐标
		config.stRule[i].stCoordinates[0].nX = 0;
		config.stRule[i].stCoordinates[0].nY = 0;
		config.stRule[i].stCoordinates[1].nX = 8191;
		config.stRule[i].stCoordinates[1].nY = 0;
		config.stRule[i].stCoordinates[2].nX = 8191;
		config.stRule[i].stCoordinates[2].nY = 8191;
		config.stRule[i].stCoordinates[3].nX = 0;
		config.stRule[i].stCoordinates[3].nY = 8191;

		// 报警相关配置(本地参数)
		config.stRule[i].stLocalParameters.bEnable = 0;    // 0 false,1 true  不需要启用的话这里至 0
		config.stRule[i].stLocalParameters.fObjectEmissivity = 0.97f;   // 目标辐射系数
		config.stRule[i].stLocalParameters.nObjectDistance = 2; // 目标距离
		config.stRule[i].stLocalParameters.nRefalectedTemp = 25; // 目标反射温度

		// 报警相关配置(测温点报警) Demo里只配置一条
		config.stRule[i].nAlarmSettingCnt = 1;
		config.stRule[i].stAlarmSetting[0].bEnable = 0; // 0 false,1 true  不需要启用的话这里至 0
		// 点测温：具体值，
		// 线测温：最大, 最小, 平均
		// 区域测温：最大, 最小, 平均, 标准, 中间, ISO
		config.stRule[i].stAlarmSetting[0].nResultType = CFG_STATISTIC_TYPE.CFG_STATISTIC_TYPE_MAX; // 最大
		config.stRule[i].stAlarmSetting[0].nAlarmCondition = CFG_COMPARE_RESULT.CFG_COMPARE_RESULT_BELOW; // 低于
		config.stRule[i].stAlarmSetting[0].fThreshold = 20.0f;  // 报警阈值温度
		config.stRule[i].stAlarmSetting[0].fHysteresis = 0.1f;  // 温度误差
		config.stRule[i].stAlarmSetting[0].nDuration = 30;      // 阈值温度持续时间(秒)
	}

}
